package com.isasc.demo.pooled.mypool;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * @author: ywy
 * @date: 2022-10-17
 * @desc:
 * 1. 空闲对象池和使用对象池
 * 2. 最大数量控制
 * 3. 有借有还
 */
@Slf4j
public class MyPool<T> {

    private Set<T> activeSet = Collections.synchronizedSet(new HashSet<>());

    private Set<T> idleSet = Collections.synchronizedSet(new HashSet<>());

    private int maxSize = 8;

    private Object lock = new Object();

    public MyPool(int maxSize) {
        this.maxSize = maxSize;
    }

    public synchronized T borrowObject(Class<T> clazz) throws Exception {
        T obj = null;
        // 借对象过程
        // 1. 尝试从空闲对象获取
        if (idleSet.size() > 0) {
            obj = idleSet.iterator().next();
        }
        // 2. 判断是否复用对象
        if (obj == null) {
            // 3. 创建对象
            int total = idleSet.size() + activeSet.size();
            if (total >= maxSize) {
                // 3.1 阻塞
                synchronized (lock) {
                    lock.wait();
                }
                // 3.2 获取有对象信号
                return borrowObject(clazz);
            }
            Method init = clazz.getMethod("init");
            obj = (T) init.invoke(obj);
            activeSet.add(obj);
        } else {
            idleSet.remove(obj);
            activeSet.add(obj);
        }
        log.info("pool size total:{},active:{},idle:{}",
                activeSet.size() + idleSet.size(),
                activeSet.size(), idleSet.size());
        return obj;
    }

    public synchronized void returnObj(T obj){
        if(obj != null) {
            activeSet.remove(obj);
            idleSet.add(obj);
            // 发送唤醒阻塞信号
            synchronized (lock){
                lock.notify();
            }
        }
    }
}
